package com.tarena.demo.luban.all.main.consumer;

import com.tarena.demo.luban.all.main.service.OrderService;
import com.tarena.demo.luban.commons.exception.BusinessDemoException;
import com.tarena.demo.luban.protocol.order.param.OrderAddParam;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

/**
 * 整合springboot 消费者代码 三步曲
 * 1. 容器bean对象
 * 2. 实现接口 指定消费对象泛型(MessageExt OrderAddParam)
 * 3. 使用注解 定义底层消费者参数 主题 分组 过滤tag 消费模式
 */
@Component
@Slf4j
@RocketMQMessageListener(topic="order-topic",consumerGroup="order-add-consumer")
public class OrderAddConsumer implements RocketMQListener<OrderAddParam> {
    @Autowired
    private OrderService orderService;
    @Autowired
    private StringRedisTemplate stringRedisTempalte;
    @Override public void onMessage(OrderAddParam message) {
        ValueOperations opsForValue = stringRedisTempalte.opsForValue();
        //当前消息中业务数据的锁的key值
        String keyLock="luban:demo:order:add:"+message.getOrderSn()+".lock";
        //生成一个当前业务的随机值 四位数字
        String rand=new Random().nextInt(9000)+"";
        try{
        //消费开始
        //1. 抢锁
            //利用redis执行抢锁方法 setnx key value 抢成功字后 设置超时 expire key 10 没抢成功不设置
            Boolean tryLock=opsForValue.setIfAbsent(keyLock,rand,10,TimeUnit.SECONDS);
            while (!tryLock){
                //3.等待
                Thread.sleep(5000);
                tryLock=opsForValue.setIfAbsent(keyLock,rand,10,TimeUnit.SECONDS);
            }
            //2. 执行业务
            orderService.addOrder(message);
            //思考题:如何在代码落地 没抢到等待5秒重抢的逻辑 提示 do while或者while
        //消费结束
        }catch (BusinessDemoException e){
            log.error("订单新增失败",e);
        }catch (InterruptedException e){
            log.error("订单新增失败",e);
        } catch(Throwable e){
            log.error("订单新增失败",e);
            throw e;
        }finally{
            //4.手动释放
            String valueLock = (String) opsForValue.get(keyLock);
            if (rand.equals(valueLock)){
                stringRedisTempalte.delete(keyLock);
            }
        }
    }
}
